home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / news / misc / eep / eep1_9 / eepmisc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-21  |  15.5 KB  |  604 lines

  1. /*
  2.  *  eepmisc.c  -- Miscellaneous functions 
  3.  */
  4.  
  5. #include    <stdio.h>
  6. #include    <ctype.h>
  7. #include    <string.h>
  8. #include    <curses.h>
  9.  
  10. #ifdef DOS
  11. #include    <dos.h>
  12. #endif /* DOS */
  13.  
  14. #ifdef UNIX
  15. #include    <ctype.h>
  16. #include    <signal.h>
  17. #endif /* UNIX */
  18.  
  19. #ifdef ANSI
  20. #include <stdlib.h>
  21. #else
  22. #define void int
  23. #ifndef size_t
  24. #define size_t unsigned
  25. #endif
  26. extern char *malloc();
  27. #endif /* ANSI */
  28.  
  29. #include    "eep.h"                  /* local changes */
  30.  
  31. extern int     qcompare();        /* sort alphabetically */
  32. extern void    cleanup();         /* graceful exit */
  33. extern char    *shift_lower();    /* see eepmisc.c */
  34. extern void    showlist();        /* eepmenu.c */
  35. extern char    buffer[],          /* general purpose line buffer */
  36.                tmp[];
  37.  
  38. extern int  i_active,   /* index into arrays */
  39.     c_active,    /* number of lines in act array */
  40.     eepoint;     /* pointer switch */
  41.  
  42. extern int eeplines;
  43. extern int eepcolumns;
  44. extern int current;
  45. extern int scrnpos;
  46. extern int top;
  47. extern int slider;
  48.  
  49. /* The levels array contains the Head pointers which control the
  50. linked lists of newsgroups grouped by their "depth" in the
  51. hierarchy, and sorted alphabetically.  E.g. alt, sci, soc are 
  52. level 0, alt.pagan, sci.physics are level 1 and so on. */
  53.  
  54. extern struct actif *levels[];  /* keep track of levels with this array */
  55. extern struct actif *aptr;    /* temporary pointer */
  56. extern struct  actif *act[];    /* main data structure */
  57.  
  58. extern int    i_levels;    /* index into array */
  59.  
  60.  
  61. WINDOW    *over;    /* used for on-screen help window etc. */
  62. void sleep();    /* forward reference */
  63.  
  64. /* These next four variables are used by wallop() */
  65.  
  66. char    *nextchunk;   /* point past most recent allocation */
  67. size_t  measure = 0;  /* how much is left? */
  68. extern char    *buffer_city[];
  69. extern int     malloc_count;
  70.  
  71.  
  72. /* wallop() -- wrapper for malloc() with safety and efficiency
  73.  *
  74.  * EEP is characterized by lots of use of malloc(), especially
  75.  * with small (possibly single-byte) sizes.  This can impose
  76.  * overhead on any system.  To make things more efficient, 
  77.  * wallop() is a wrapper for malloc() that will bite off
  78.  * much larger chunks of memory (defined in eep.h) using
  79.  * malloc(), and slice bits off when EEP needs them.
  80.  * The price we pay is slightly less efficient use of
  81.  * memory, as wallop() will not assume that successive
  82.  * calls to malloc() will return contiguous memory addresses.
  83.  *
  84.  * If EEP calls wallop() with a size larger than WALLOP_SIZE,
  85.  * wallop() will simply pass the buck to malloc().
  86.  *
  87.  * As each large buffer is allocated with malloc(), the pointer
  88.  * is stored in buffer_city[] so that they can easily be
  89.  * freed when the program finishes.
  90.  */
  91.  
  92. char      *wallop(size_wanted)
  93. size_t    size_wanted;
  94. {
  95. char           *walloper;    /* point at start of chunk */
  96.  
  97.     if (size_wanted <= 0) 
  98.         return((char *)NULL);  /* safety */
  99.     
  100.     /* ensure the next wallop is aligned correctly -- this is
  101.      * necessary otherwise certain machine architectures will
  102.      * core dump if you store a pointer or integer with the
  103.      * wrong byte alignment. */
  104.     while ((size_wanted % ALIGNMENT) != 0) size_wanted++;
  105.  
  106.     if (size_wanted >= WALLOP_SIZE) {
  107.         walloper = (char *)malloc(size_wanted);
  108.         if (walloper == (char *)NULL) {
  109.             fprintf(stderr,"Fatal error while allocating memory!\n");
  110.             cleanup();
  111.         }
  112.         buffer_city[malloc_count++] = walloper;
  113.         return(walloper);
  114.     }
  115.  
  116.     if (size_wanted > measure) {   /* need a new malloc() */
  117.         nextchunk = (char *)malloc(WALLOP_SIZE);
  118.         if (nextchunk == (char *)NULL) {
  119.             fprintf(stderr,"Fatal error while allocating memory!\n");
  120.             cleanup();
  121.         }
  122.         buffer_city[malloc_count++] = nextchunk;
  123.         measure = WALLOP_SIZE;
  124.     }
  125.  
  126.     walloper = nextchunk;
  127.     nextchunk += size_wanted;
  128.     measure  -= size_wanted;
  129.     return(walloper);
  130. }
  131.  
  132.     
  133. /* getbuf() -- read input into the buffer */
  134.  
  135. void    getbuf(buf,max)
  136. char    *buf;
  137. int     max;     /* maximum number of characters to get */
  138. {
  139. int    count = 0,
  140.     c;    /* character */
  141.  
  142.     while ((count < BUFSIZE - 1) &&
  143.            (count < max)) { /* -1 to allow for nul */
  144.         c = getch();
  145.         switch(c) {
  146.         case '\033':
  147.         case '\003':
  148. #ifdef KEY_EXIT
  149.         case KEY_EXIT:
  150. #endif
  151. #ifdef KEY_BREAK
  152.         case KEY_BREAK:
  153. #endif
  154.             deleteln();
  155.             refresh();
  156.             buf[0] = '\0';
  157.             return;
  158.             break;    /* just in case */
  159.         case '\010':
  160.         case '\177':
  161. #ifdef KEY_LEFT
  162.         case KEY_LEFT:
  163. #endif
  164. #ifdef KEY_BACKSPACE
  165.         case KEY_BACKSPACE:
  166. #endif
  167. #ifdef KEY_DL
  168.         case KEY_DL:
  169. #endif
  170.             if (count == 0)    continue;
  171.             addstr("\010 \010");
  172.             refresh();
  173.             count--;
  174.             continue;
  175.  
  176.         case '\n':
  177.         case '\r':
  178. #ifdef KEY_ENTER
  179.         case KEY_ENTER:
  180. #endif
  181.             buf[count] = '\0';
  182.             return;
  183.             break;
  184.         }
  185.         /* yes, this is very ASCII and doesn't take into
  186.         account non-English alphabets.  This is because
  187.         I'm not planning to fix curses in free software. */
  188.         if ((c < '\020') || /* some other control code */
  189.             (c > '\177'))
  190.             continue;    /* ignore it */
  191.         buf[count] = c;
  192.         addch(buf[count]);
  193.         refresh();
  194.         count++;
  195.     }
  196.     buf[count] = '\0';    /* nul terminate the string */
  197. }
  198.  
  199. /* wrap -- this function will take a string, and word wrap it to
  200. within the defined width by inserting CRLF at appropriate places. 
  201. The result will be output directly.  An offset may be defined, 
  202. which will not be used on the first line only. */
  203.  
  204. void    wrap(string,width,offset)
  205. char    *string;
  206. int    width,
  207.     offset;
  208. {
  209. static char    temp[80];    /* temporary buffer */
  210. char    *p,*q;    /* traverse the string with this */
  211. int    count;    /* keep track of characters */
  212. int    offcount;
  213. int    first_line;
  214.  
  215.     temp[0] = '\0';
  216.     if (string == (char *)NULL) return;
  217.     if (width == 0) {
  218.         printf("Can't wrap to zero width, sorry!",CRLF);
  219.         return;
  220.     }
  221.     if (strlen(string) == 0) return;
  222.     p = string;
  223.     q = temp;
  224.     count = 0;
  225.     first_line = 0;    /* no offset for first line */
  226.     while (*p != '\000') {
  227.         *q = *p;
  228.         if (count == width) { /* check for wrapping */
  229.             while (*p != ' ') {
  230.                 q--;
  231.                 p--;
  232.                 if (--count == 0) { /* can't wrap! */
  233.                     /* so we truncate */
  234.                     q = temp + width;
  235.                     p = p + width; /* carry on... */
  236.                     break;
  237.                 }
  238.             }
  239.             *q = '\0';  /* terminate output here */
  240.             if (first_line != 0) {
  241.                 offcount = offset;
  242.                 while (offcount-- > 0) printf(" ");
  243.             }
  244.             first_line = 1;
  245.             printf(temp,CRLF);
  246.             count = -1;    /* new line */
  247.             q = temp - 1;
  248.         }
  249.         count++;
  250.         p++;
  251.         q++;
  252.     }
  253.     *q = '\0';
  254.     if (first_line != 0) {
  255.         offcount = offset;
  256.         while (offcount-- > 0) printf(" ");
  257.     }
  258.     printf(temp,CRLF);
  259. }
  260.  
  261.  
  262. /* These next two routines simply lifted from the Elm mail package, 
  263. by Dave Taylor.  If you need a nice mail system, you won't have to 
  264. look much further than Elm!  -- P.G. */
  265.  
  266. char    *shift_lower(string)
  267. char    *string;
  268. {
  269.     /** return 'string' shifted to lower case.  Do NOT touch the
  270.         actual string handed to us! **/
  271.  
  272.     static char buf[BUFSIZE];
  273.     register char *bufptr = buf;
  274.  
  275.         if (string == (char *)NULL) {
  276.             *bufptr = '\0';
  277.             return((char *)buf);
  278.         }
  279.  
  280.     for (; *string; string++, bufptr++)
  281.       if (isupper(*string))
  282.         *bufptr = tolower(*string);
  283.       else
  284.         *bufptr = *string;
  285.     
  286.     *bufptr = 0;
  287.     
  288.     return( (char *) buf);
  289. }
  290.  
  291. #ifdef DOS
  292. /*
  293.  *  Here are some timing routines.  Call msleep() with parameter
  294.  *  of 0L to establish precision the first time. 
  295.  */
  296.  
  297.  
  298. typedef struct
  299. { /* time holder */
  300.   int hour;
  301.   int minute;
  302.   int sec;
  303.   int hsec;
  304. } TIME, *TIME_PTR;
  305.  
  306. #define GET_TIME    0x2c      /* time request       */
  307. #define DOS_INT     0x21      /* int to call DOS    */
  308. #define INIT        60        /* initial clock set  */
  309.  
  310. /*
  311.  * get_time(n)
  312.  * TIME_PTR n;
  313.  *
  314.  * fills timetype structure n with current time using DOS interrupt 21
  315.  *
  316.  */
  317.  
  318. get_time(n)
  319. TIME_PTR n;
  320. {
  321.   union REGS inregs;
  322.   union REGS outregs;
  323.  
  324.   inregs.h.ah = GET_TIME;
  325.  
  326.   int86(DOS_INT, &inregs, &outregs);
  327.  
  328.   n->hour =   outregs.h.ch;
  329.   n->minute = outregs.h.cl;
  330.   n->sec  =   outregs.h.dh;
  331.   n->hsec =   outregs.h.dl;
  332.  
  333.   return(0);
  334. }
  335.  
  336. /* This will sleep for x seconds. */
  337.  
  338. void    sleep(x)
  339. int x;
  340. {
  341.   int i;
  342.   unsigned s;
  343.   TIME n;               /* current time record */
  344.  
  345.   i = 0;
  346.   get_time(&n);
  347.   s = n.sec;
  348.  
  349.   while (i < x){
  350.     while (s == n.sec)
  351.       get_time(&n);
  352.     s = n.sec;
  353.     ++i;
  354.   }
  355. }
  356.  
  357. void    msleep(ms)
  358.   long ms;
  359. { /* sleep for ms miliseconds */
  360.   static long estimate = 20L; /* loops per milisecond */
  361. #define OFFSET 20L
  362.   long loops;
  363.   TIME n1, n2;
  364.   unsigned int mydelay;
  365.   
  366.   /* If the value is 0, then we try to calculate the number of miliseconds
  367.    * that make up a clock tick, then estimate a timing loop that will
  368.    * delay for 1 milisecond.  */
  369.  
  370.   if (ms == 0L) {
  371.  
  372.     /* Loop until we see a change in time. */
  373.  
  374. try_again:
  375.     get_time(&n1);
  376.     for (loops = estimate*10; loops == 0; loops--)
  377.         loops = (loops << 1) / 2; 
  378.     get_time(&n2); 
  379.     printf("Estimating... %ld\n", estimate);
  380.     
  381.     if ((n1.hsec == n2.hsec) && (n1.sec == n2.sec)) {
  382.     estimate += OFFSET;
  383.     goto try_again;
  384.     }
  385.  
  386.     /* Calculate the difference in hundredths of seconds.  Note
  387.      * that is is possible that n2.sec is less than n1.sec if
  388.      * the minute has just changed, in which case we cheat.
  389.      */
  390.     if (n2.minute != n1.minute) n2.sec = n1.sec + 1;
  391.     mydelay = (100*n2.sec + n2.hsec) - (100*n1.sec + n1.hsec);
  392.  
  393.     /* this is the first guess */
  394.     estimate = estimate / ((long)mydelay * 10);
  395.  
  396.     get_time(&n1);
  397.     for (loops = INIT*estimate*10; loops > 0; loops--)
  398.         loops = (loops << 1) / 2;
  399.     get_time(&n2);
  400.     if (n2.minute != n1.minute) n2.sec = n1.sec + 1;
  401.     mydelay = (100*n2.sec + n2.hsec) - (100*n1.sec + n1.hsec);
  402.     if (mydelay == 0) mydelay = INIT;
  403.     estimate = (INIT*estimate) / ((long)mydelay);
  404.     printf("Estimate %ld loops per millisecond\n",estimate);
  405.     for (loops = 10; loops > 0; loops--) {
  406.     printf("Tick... ");
  407.         msleep(1000L);
  408.     }
  409.     printf(" BOOM!\n");
  410.   }
  411.   for (loops = (long)ms*estimate; loops > 0; loops--)
  412.     loops = (loops << 1) / 2; /* do nothing really */
  413. }
  414. #endif /* DOS */
  415.  
  416. /* These in_string routines borrowed from ELM by Dave Taylor. */
  417.  
  418. int 
  419. in_string_r(buf, pat, mark)
  420. char *buf, *pat;
  421. int mark;
  422. {
  423.     /* Returns offset into buf iff pat occurs IN ITS ENTIRETY in buf. */
  424.  
  425.     register int i, j;
  426.  
  427.     i = mark;
  428.     while (mark >= 0) {
  429.         j = 0;
  430.         while (buf[i++] == pat[j++])
  431.             if (pat[j] == '\0')
  432.                 return (mark);
  433.         i = --mark;
  434.     }
  435.     return (-1);
  436. }
  437.  
  438. int 
  439. in_string(buf, pat, mark)
  440. char *buf, *pat;
  441. int mark;
  442. {
  443.     /* Returns offset into buf iff pat occurs IN ITS ENTIRETY in buf. */
  444.  
  445.     register int i, j;
  446.  
  447.     i = mark;
  448.     while (buf[i] != '\0') {
  449.         j = 0;
  450.         while (buf[i++] == pat[j++])
  451.             if (pat[j] == '\0')
  452.                 return (i - j);
  453.         i = i - j + 1;
  454.     }
  455.     return (-1);
  456. }
  457.  
  458.  
  459. /* Here is an EMACS-style search, kindly contributed to EEP by
  460.  * Vernon C. Hoxie.  Thanks Vern!
  461.  */
  462.  
  463. #define SEARCHBUF    60
  464. #define REVERSE      0x01
  465. #define FIRST        0x02
  466. #define LEFTWARDS    0x04
  467.  
  468. void  do_search( d )
  469. unsigned short d;
  470. {
  471.     char c;
  472.     char *p;                       /* pointers into search buffer */
  473.     char *target;
  474.     char search[SEARCHBUF];        /* search string buffer */
  475.     static char saved[SEARCHBUF];  /* old search string buffer */
  476.     int found;                     /* index into string when match found */
  477.     int position;                     /* index into act structure */
  478.     int mark;                      /* index into target array */
  479.     int mode;                      /* steering flags */
  480.     int count = SEARCHBUF;
  481.  
  482.     move(eeplines - 1, 0);
  483.     deleteln();
  484.     refresh();
  485.     p = search;
  486.     *p = '\0';
  487.     mode = FIRST;
  488.     found = 0;
  489.     mark = 0;
  490.     position = current;
  491.     if ( d == '\022' ) position--;
  492.  
  493.     while (1) {
  494.         if ( d == '\022' ) mode |= REVERSE;
  495.         else mode &= ~REVERSE;
  496.         move(eeplines - 1, 0);
  497.         printw("%s search: %s", (mode&REVERSE)?"Reverse":"Forward", search);
  498.         clrtoeol();
  499.         move(scrnpos, found);
  500.         refresh();
  501.         c = getch();
  502.         if ( c >= ' ' && c < '\177' ) {
  503.             if ( isupper(c) ) c = tolower(c);
  504.             *p++ = c;
  505.             *p = '\0';
  506.             if ( --count <= 0 ) break;
  507.         }
  508.         else if ( c == '\010' && p != search ) {    /* Backspace */
  509.             *(--p) = '\0';
  510.             count++;
  511.             mode ^= REVERSE;
  512.             if ( mode & REVERSE ) mark--;
  513.             else mark++;
  514.         }
  515.         else if ( c == '\022' || c == '\023' ) {    /* ^R || ^S */
  516.             if ( search[0] == '\0' ) {
  517.                 strcpy(search,saved);
  518.             }
  519.             else if ( c != d ) {
  520.                 mode ^= REVERSE | FIRST;
  521.                 d = c;
  522.             }
  523.             if ( mode & REVERSE ) {
  524.                 if ( --mark < 0 ) {
  525.                     position--;
  526.                     mode |= FIRST;
  527.                 }
  528.             } 
  529.             else mark++;
  530.         }
  531.         else if ( c == '\033' ) {                /* ESCape */
  532.             fflush( stdin );
  533.             break;
  534.         }
  535.  
  536.         found = 0;
  537.         do {
  538.             if ((aptr = act[position]) == (struct actif *) NULL) break;
  539.             if ( mode & REVERSE ) {
  540.                 if ( mode & FIRST ) {
  541.                     target = aptr->desc;
  542.                     mode &= ~LEFTWARDS;
  543.                 }
  544.                 else {
  545.                     target = aptr->name;
  546.                     mode |= LEFTWARDS;
  547.                 }
  548.                 if ( mark < 0 ) mark = strlen(target);
  549.                 mark = in_string_r(shift_lower(target), search, mark);
  550.             }
  551.             else {
  552.                 if ( mode & FIRST ) {
  553.                     target = aptr->name;
  554.                     mode |= LEFTWARDS;
  555.                 }
  556.                 else {
  557.                     target = aptr->desc;
  558.                     mode &= ~LEFTWARDS;
  559.                 }
  560.                 if ( mark < 0 ) mark = 0;
  561.                 mark = in_string(shift_lower(target), search, mark);
  562.             }
  563.             if ( mark < 0 ) {
  564.                 if ( mode & FIRST ) mode ^= FIRST;
  565.                 else {
  566.                     if ( mode & REVERSE ) {
  567.                         if ( --position < 0) position = c_active - 1;
  568.                     }
  569.                     else if ( ++position >= c_active ) position = 0;
  570.                     mode |= FIRST;
  571.                     if ( position == current ) break;
  572.                 }
  573.             }
  574.             else {
  575.                 if ( mode & LEFTWARDS ) {
  576.                     if (( found = mark + 3 ) > 32 ) found = 32;
  577.                 }
  578.                 else if (( found = mark + 32 ) > eepcolumns )
  579.                             found = eepcolumns - 1;
  580.             }
  581.  
  582.         } while ( found < 3 );
  583.         current = position;
  584.         if ( found > 0 ) {
  585.             showlist(current, 0);
  586.         }
  587.         else {
  588.             beep();
  589.             move(eeplines - 1, 0);
  590.             printw("Search failed");
  591.             clrtoeol();
  592.             refresh();
  593.             sleep(1);
  594.         }
  595.     }
  596.     strcpy(saved,search);
  597.     move(eeplines - 1, 0);
  598.     deleteln();
  599.     showlist(current,0);
  600.     refresh();
  601.     return;
  602. }
  603.  
  604.